using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace CriticalSystems.Instrumentation.LogWriters
{
    public class ExceptionInfo
    {
        private readonly Guid id;
        private readonly Exception exception;
        private readonly string properties;
        private string tracing;

        public ExceptionInfo(Exception exception)
        {
            this.id = Guid.NewGuid();
            this.exception = exception;
            this.properties = BuildExceptionPropertiesText(exception);
        }

        private static string BuildExceptionPropertiesText(Exception ex)
        {
            IList<KeyValuePair<string, object>> exceptionProperties = GetExceptionProperties(ex);
            StringBuilder builder = new StringBuilder();
            foreach (KeyValuePair<string, object> pair in exceptionProperties)
            {
                if (builder.Length > 0)
                {
                    builder.Append(", ");
                }
                builder.AppendFormat("{0}={1}", pair.Key, pair.Value);
            }
            return builder.ToString();
        }

        private static IList<KeyValuePair<string, object>> GetExceptionProperties(Exception ex)
        {
            MemberInfo[] properties = ex.GetType().FindMembers(MemberTypes.Property,
                                                               BindingFlags.Public | BindingFlags.Instance,
                                                               delegate(MemberInfo target, object criteria)
                                                                   {
                                                                       bool include = true;
                                                                       foreach (string name in (string[])criteria)
                                                                       {
                                                                           if (target.Name == name)
                                                                           {
                                                                               include = false;
                                                                               break;
                                                                           }
                                                                       }
                                                                       return include;
                                                                   },
                                                               new string[]
                                                                   {
                                                                       "Message", "TargetSite", "StackTrace",
                                                                       "InnerException", "HelpLink", "Data", "Source"
                                                                   });
            IList<KeyValuePair<string, object>> propertyNamesAndValues = new List<KeyValuePair<string, object>>();
            foreach (MemberInfo property in properties)
            {
                object value = ex.GetType().InvokeMember(property.Name, BindingFlags.GetProperty, null, ex, null);
                KeyValuePair<string, object> pair = new KeyValuePair<string, object>(property.Name, value);
                propertyNamesAndValues.Add(pair);
            }
            return propertyNamesAndValues;
        }

        public string Id
        {
            get { return this.id.ToString(); }
        }

        public Exception Exception
        {
            get { return this.exception; }
        }

        public string Properties
        {
            get { return this.properties; }
        }
        public string Tracing
        {
            get { return this.tracing; }
            set { this.tracing = value; }
        }
    }
}